package org.elanfox.cloud.mybatis.base;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.elanfox.cloud.mybatis.annotations.CreateTime;
import org.elanfox.cloud.mybatis.annotations.UpdateTime;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.Properties;

/**
 * @author allan
 * @version 1.0.0
 * @date 2020/7/2
 */
@Component
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class MybatisTimeInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];

        // 获取 SQL 命令
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();

        // 获取参数
        Object parameter = invocation.getArgs()[1];

        // 获取私有成员变量
        Field[] declaredFields;
        if (parameter instanceof Base2PO) {
            Class superClass = parameter.getClass().getSuperclass();

            while (true) {
                if (superClass == BasePO.class) {
                    declaredFields = superClass.getSuperclass().getDeclaredFields();
                    break;
                }
                if (superClass == Base2PO.class) {
                    declaredFields = superClass.getDeclaredFields();
                    break;
                }
                superClass = superClass.getSuperclass();
            }

            for (Field field : declaredFields) {
                if (field.getAnnotation(CreateTime.class) != null) {
                    if (SqlCommandType.INSERT.equals(sqlCommandType)) { // insert 语句插入 createTime
                        field.setAccessible(true);
                        field.set(parameter, LocalDateTime.now());
                    }
                }

                if (field.getAnnotation(UpdateTime.class) != null) { // insert 或 update 语句插入 updateTime
                    if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
                        field.setAccessible(true);
                        field.set(parameter, LocalDateTime.now());
                    }
                }
            }

            return invocation.proceed();
        }

        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
